(Originally posted on my Portuguese blog at rberaldo.com.br)
Starting from PHP 5.5, the MySQL library in PHP, with functions like mysql_connect
and mysql_query
, is considered outdated. I talked about this in this post. The most recommended alternative is to use the PDO extension.
However, many programmers still don’t know how to use PDO. I will show in this post how simple it is to use this class.
It’s very important to use PDO for two main reasons:
- Your code becomes cleaner and more modern.
- It’s easy to migrate to another Database Management System (DBMS) if necessary in the future.
But if you are reading this post, you probably already know that.
What Is PDO
PDO stands for PHP Data Objects. It is a class for managing database connections. Yes, databases. This means you can use PDO to connect to many DBMS, including MySQL, PostgreSQL, SQLite, MS SQL Server, Oracle, and others.
PDO Is Object-Oriented
PDO is a class. It follows the Object-Oriented Programming (OOP) paradigm. If you’re not familiar with OOP, I recommend studying it a bit before using PDO.
You don’t need to go too deep. Just understand what classes, objects, and methods are. Learn how to instantiate objects and call their methods. That’s sufficient to work with PDO.
Table Used for This Tutorial
I’ve created a table called “programmers” with ID, name, and website for each of them. I used the following SQL to create the table and its data:
CREATE TABLE programmers(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(80) NOT NULL,
website VARCHAR(120) DEFAULT NULL,
PRIMARY KEY(id)
);
INSERT INTO programmers(name, website) VALUES
('Beraldo', 'https://beraldo.dev'),
('John', NULL),
('Mary', 'http://mariaprogramadora.com.br'),
('Joseph', 'http://joseprogramador.com.br'),
('Linus Torvalds', 'http://kernel.org'),
('Mark Zuckerberg', 'http://facebook.com'),
('Steve Wozniak', 'http://apple.com');
Connecting to MySQL Using PDO
Let’s define constants to store the connection data:
define('MYSQL_HOST', 'localhost');
define('MYSQL_USER', 'root');
define('MYSQL_PASSWORD', '');
define('MYSQL_DB_NAME', 'pdo_tutorial');
The connection is established by the constructor of the PDO class. That is, you just need to pass the connection data as parameters when you instantiate the PDO class, like this:
$PDO = new PDO('mysql:host='. MYSQL_HOST . ';dbname=' . MYSQL_DB_NAME, MYSQL_USER, MYSQL_PASSWORD);
This works. However, if the connection fails, an exception will be thrown, and the execution will be stopped.
To avoid this, we should put this code in a try…catch block and handle the PDOException exception. The code will look like this:
try {
$PDO = new PDO('mysql:host=' . MYSQL_HOST . ';dbname=' . MYSQL_DB_NAME, MYSQL_USER, MYSQL_PASSWORD);
} catch (PDOException $e) {
echo 'Erro ao conectar com o MySQL: ' . $e->getMessage();
}
Setting UTF-8 Encoding
To set UTF-8 encoding (or another encoding if you are not already using UTF-8), execute the following query right after opening the connection:
phpCopy code
$PDO->exec("set names utf8");
Executing SELECT with PDO
With the instance of the PDO class in the variable $PDO, you can perform a simple SELECT like this:
$sql = "SELECT * FROM programmers";
$result = $PDO->query($sql);
$rows = $result->fetchAll();
print_r($rows);
The query
method of the PDO class executes a query and, in the case of SELECT, returns an object of type PDOStatement. This object has the fetchAll
method, which is similar to the mysql_fetch_array
function, returning an array with all the records. We use the print_r
function to display this array. The output will be like this:
Array
(
[0] => Array
(
[id] => 1
[0] => 1
[nome] => Beraldo
[1] => Beraldo
[site] => https://beraldo.dev
[2] => https://beraldo.dev
)
[1] => Array
(
[id] => 2
[0] => 2
[nome] => John
[1] => John
[site] =>
[2] =>
)
[2] => Array
(
[id] => 3
[0] => 3
[nome] => Mary
[1] => Mary
[site] => http://mariaprogramadora.com.br
[2] => http://mariaprogramadora.com.br
)
[3] => Array
(
[id] => 4
[0] => 4
[nome] => Joseph
[1] => Joseph
[site] => http://joseprogramador.com.br
[2] => http://joseprogramador.com.br
)
[4] => Array
(
[id] => 5
[0] => 5
[nome] => Linus Torvalds
[1] => Linus Torvalds
[site] => http://kernel.org
[2] => http://kernel.org
)
[5] => Array
(
[id] => 6
[0] => 6
[nome] => Mark Zuckerberg
[1] => Mark Zuckerberg
[site] => http://facebook.com
[2] => http://facebook.com
)
[6] => Array
(
[id] => 7
[0] => 7
[nome] => Steve Wozniak
[1] => Steve Wozniak
[site] => http://apple.com
[2] => http://apple.com
)
)
For each record, you’ll see duplicated values. They appear in two indices: one is the field number in the table, and the other is the field name. This consumes double the memory. That’s why it’s recommended to return only the record with the field names.
To do that, pass the PDO::FETCH_ASSOC
parameter to the fetchAll
method. It will work similarly to the mysql_fetch_assoc
function, returning only the associative array with field names. Change the line calling the fetchAll
method like this:
$rows = $result->fetchAll(PDO::FETCH_ASSOC);
The displayed array will look like this:
Array
(
[0] => Array
(
[id] => 1
[nome] => Beraldo
[site] => https://beraldo.dev
)
[1] => Array
(
[id] => 2
[nome] => John
[site] =>
)
[2] => Array
(
[id] => 3
[nome] => Mary
[site] => http://mariaprogramadora.com.br
)
[3] => Array
(
[id] => 4
[nome] => Joseph
[site] => http://joseprogramador.com.br
)
[4] => Array
(
[id] => 5
[nome] => Linus Torvalds
[site] => http://kernel.org
)
[5] => Array
(
[id] => 6
[nome] => Mark Zuckerberg
[site] => http://facebook.com
)
[6] => Array
(
[id] => 7
[nome] => Steve Wozniak
[site] => http://apple.com
)
)
Filtering Queries
Usually, our SELECT queries have a WHERE clause to filter results. It’s straightforward to do using PDO.
Let’s consider the following situation: we will request the user to define a string to use as a filter in the SELECT. The filtering will be done on the “site” field of our table.
$search = $_GET['search'];
$sql = "SELECT * FROM programmers WHERE website LIKE '%" . $search . "%'";
$result = $PDO->query($sql);
$rows = $result->fetchAll(PDO::FETCH_ASSOC);
Suppose the user entered the word “programmer.” Therefore, $_GET['search']
will be the string “programmer.”
The $rows
array will look like this:
Array
(
[0] => Array
(
[id] => 3
[nome] => Maria
[site] => http://mariaprogramadora.com.br
)
[1] => Array
(
[id] => 4
[nome] => Joseph
[site] => http://joseprogramador.com.br
)
)
But there is a more efficient and secure way to pass parameters for queries: using Prepared Statements.
What Are Prepared Statements and How to Use Them
Prepared Statements are useful for executing the same query multiple times with different parameters efficiently. However, they also serve another purpose: native query filtering to prevent SQL Injection, adding extra security to your system.
In this type of query, parameters are not sent directly in the query. They are sent in a separate “package” to the MySQL server. The server then associates the SQL string with the parameters.
In other words, we won’t directly put the $search
variable in the query.
With Prepared Statements, your code will look like this:
$search = $_GET['search'];
$search = '%' . $search . '%';
$sql = "SELECT * FROM programmers WHERE website LIKE :search";
$stmt = $PDO->prepare($sql);
$stmt->bindParam(':search', $search);
$result = $stmt->execute();
Now, our query contains only the value “:search” in the WHERE clause. This is how the query will be sent to MySQL. With the bindParam
method, we specify that we want to send the value of $search
, which will replace :search
.
Since we are using LIKE
, we had to manually add the percentage signs (%) on the second line. If we were searching for exact strings (with the = operator), we wouldn’t need that.
The $rows
array will be the same as in the previous code.
Using Prepared Statements makes your code much safer. You can also specify the data type by passing the third parameter to bindParam
. The possible values are:
PDO::PARAM_BOOL
PDO::PARAM_NULL
PDO::PARAM_INT
PDO::PARAM_STR
(this is the default value)PDO::PARAM_LOB
These parameters tell MySQL how to treat each value. For example, strings need to be enclosed in single quotes, but integers don’t. That’s why it’s important to pass these parameters when the value is not a string.
INSERT, DELETE, and UPDATE Using PDO
These three commands will be handled similarly. Here’s how to perform an INSERT:
$name = 'Bill Gates';
$website = 'http://microsoft.com';
$sql = "INSERT INTO programmers(name, website) VALUES(:name, :website)";
$stmt = $PDO->prepare($sql);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':website', $website);
$result = $stmt->execute();
if (!$result) {
var_dump($stmt->errorInfo());
exit;
}
echo $stmt->rowCount() . " lines inserted";
Let’s assume that $name
and $website
come from a form. Therefore, we need to filter these values using Prepared Statements.
For the UPDATE operation, let’s assume we want to change the “website” value to “http://windows.com.br” for the name “Bill Gates.” The code is as follows:
$name = 'Bill Gates';
$website = 'http://ruindows.com.br';
$sql = "UPDATE programmers set website = :website WHERE name = :name";
$stmt = $PDO->prepare($sql);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':website', $website);
$result = $stmt->execute();
if (!$result) {
var_dump($stmt->errorInfo());
exit;
}
echo $stmt->rowCount() . " lines updated";
The DELETE operation will look like this:
$name = 'Bill Gates';
$sql = "DELETE FROM programmers WHERE name = :name";
$stmt = $PDO->prepare($sql);
$stmt->bindParam(':name', $name);
$result = $stmt->execute();
if (!$result) {
var_dump($stmt->errorInfo());
exit;
}
echo $stmt->rowCount() . " lines removed";
Conclusion
I hope you found this tutorial useful. There are many other features of the PDO extension. You can read about them all in the Official Extension Documentation.
Muito bom!!!
Estou meio enferrujado no PHP e preciso lembrar para dar aulas rsrs. Muito legal essas novas funções do PHP 7.
Olá.
O PDO existe, na verdade, desde o PHP 5.1.
O PHP 7 removeu a extensão mysql, recomendando usar mysqli ou PDO (ambos já existiam há anos).
Se quiser conhecer as novidades do PHP 7, veja este meu curso gratuito: http://cursophp7.ultimatephp.com.br
Obrigado Beraldo por compartilhar essa informação.
Olá, Antonio.
Que bom que o artigo foi útil pra você 🙂
Abraço
Comecei a estudar PHP há poucas semanas, daí nas pesquisas que fiz eu vi que o PDO é o mais recomendado e estou começando a estudá-lo. Muito obrigado por compartilhar esse conhecimento.
PDO é, realmente, a melhor opção. Bons estudos! 🙂
Obrigado pelo Ótimo artigo! Ajudou muito!
Mas eu tenho uma dúvida, vi em alguns lugares que pode-se usar o Prepared Statements usando a ‘?’ na $sql, mas passando o valor da ‘?’ no método execute() da PDO dentro de um array.
Exemplo:
$sql = “SELECT * FROM tabela WHERE id = ? “;
e depois na execução ficaria assim:
$query->execute( array(1) ); // Funciona normalmente
Qual é a diferença dessa forma de informar o valor, para as formas que passam valores pelos ” bind’s ” ? Além da não verificação do tipo de dado.
Desde já agradeço pelos excelentes artigos que posta aqui. Estão me ajudando muito em meus estudos sobre o PHP OO.
Muito Obrigado Novamente!
Eu não gosto muito dessa forma, principalmente quando há muitos parâmetros. Aí fica assim:
->prepare(‘SELECT … WHERE para1 = ?, param2 = ?, param3 =? …’)
->execute(‘param1’, ‘param2’, ‘param3’…);
Acho que fica pouco legível. Mas pra quando há poucos parâmetros, não tem problema.
No “prepare” não tem como fugir kkk ou então, joga todo o select pra uma variável $sqlSelect e cria um array de parâmetros executando somente o array. Por exemplo:
$stmt = $pdo->prepare($sqlSelect);
$p[“:descricao”] = $descricao;
$p[“:estoque”] = $estoque;
$p[“:preco”] = $preco;
$p[“:validade”] = $validade;
if ($stmt->execute($p))
…..
Beraldo, qual a diferença entre bindParam e bindValue?
Muito bom seu artigo bem claro! Eu fiz uns códigos para tá passando um valor de uma página que resgata os dados e atribui a uma variável em outra página pelo método Post vou ver se com as suas explicações funciona agora pois ela envia o valor mais não realiza a deleção nem a edição e não acho erro caso não funcione postarei aki para vc me ajudar! Já agradeço pelo ótimo Post seu Beraldo
Obrigado por compartilhar o artigo. Vejo muitas dúvidas sobre o PDO, e achei seu artigo muito completo. Parabéns!
Obrigado! ?
COMO CRIA BANCO DE DADOS COM PDO ???????????????? #$@
Você pode usar o método query() ou execute() para executar o comando CREATE DATABASE. Porém, em geral, as aplicações não criam o banco.
Obg
Muito bom, venho acompanhando seu site.
Obrigado pelo artigo!
Obrigado! Que bom que foi útil 🙂
A tempos já trabalhava com a conexão PDO, porém agora..passei para o php 7 e simplismente não puxa nada do banco de dados. Uso o try/catch e nenhum erro aparece.
Algo parecido com algum de vocês?
Sabem resolver?
Habilite todas as exibições de erro e tente de novo. Siga este meu artigo: http://rberaldo.com.br/as-mensagens-de-erros-mais-comuns-do-php/
Boa Tarde! Podem me ajudar nesse erro?
Notice: Undefined index: digitenome in C:xampphtdocstestecadastrandonome.php on line 15
array(3) { [0]=> string(5) “23000” [1]=> int(1048) [2]=> string(34) “Column ‘digitenome’ cannot be null” }
Olá. Descrevo esse erro neste link: http://rberaldo.com.br/as-mensagens-de-erros-mais-comuns-do-php/#undef_index
não estou conseguindo pegar o conteúdo do formulário html para trabalhar com ele no php
Você deve estar errando o “name” do campo HTML. Compare o valor dele com o que está usando no índice do array $_POST
Era isso mesmo, muito obrigado.
Excelente artigo, muito útil. Parabéns!
Obrigado! 🙂
Muito bom bem explicado parabéns
Obrigado! ?
Para mim o fatchall não funcionou para usar o LIKE da forma que foi posta no site. Tive que executar assim:
$stmt = $PDO->prepare( ‘SELECT * FROM programadores WHERE site LIKE ?’ );
$stmt->execute(array($search));
$rows = $stmt->fetchAll( PDO::FETCH_ASSOC );
print_r($rows);
Valeu! Eu estou querendo aprender a usar o PDO, mas, estava com um problema, que toda vez que eu tentava fazer igual ao exemplo ou parecido, em outros lugares, dava erro(ou não funcionava igual), mas aqui funcionou. Obrigado pelo excelente tutorial.
Ruindows kkk